/*
 * File Name: Message.h
 *
 * Created on: 2021-01-28
 * Author: glendy ganby@163.com
 *
 * Last Modified: 2021-01-28
 * Description:
 */

#ifndef _MESSAGE_H_
#define _MESSAGE_H_

#include <string>
#include <vector>
#include <stdint.h>

namespace miniproto
{
class ProtoField;
class ProtoFieldDescriptor;
class MessageDescriptor;
class MessageFactory;
class BufferStream;
template<class T> class RepeatedField;

class Message
{
public:
	typedef ::std::vector< ::miniproto::ProtoField * > ProtoFieldList;
	typedef ::std::vector<bool> BoolList;
	typedef ::std::vector<int32_t> Int32List;
	typedef ::std::vector<int64_t> Int64List;
	typedef ::std::vector<uint32_t> UInt32List;
	typedef ::std::vector<uint64_t> UInt64List;
	typedef ::std::vector<float> FloatList;
	typedef ::std::vector<double> DoubleList;
	typedef ::std::vector< ::std::string * > StringList;
	typedef ::std::vector< ::miniproto::Message * > MessageList;
public:
	Message();
	virtual ~Message();
	virtual const ::std::string &GetTypeName() const;
	virtual Message* New() const = 0;
	virtual void Destroy() = 0;
	virtual void Clear(void);

	virtual int ByteSize() const;
	virtual void CopyFrom(const Message &from);
	virtual void MergeFrom(const Message &from);

	virtual bool ParseFromArray(const void *data, int size);
	virtual bool ParseFromString(const ::std::string &data);

	virtual bool SerializeToArray(void *data, int size) const;
	virtual bool SerializeToString(::std::string *output) const;
	virtual std::string SerializeAsString(void) const;

	::std::string DebugString(void) const;
	std::string Utf8DebugString(void) const;

	int FieldSize() const;
	const ProtoField *GetField(int number) const;
	const ProtoFieldDescriptor *GetFieldDescriptor(int number) const;

private:
	char *string_as_array(::std::string *output) const;
	const ProtoFieldList *field_list() const;
	bool parse_varint(::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream);
	bool parse_float(::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream);
	bool parse_double(::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream);
	bool parse_string_or_message(::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream);
	bool parse_string(::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, const uint64_t size, BufferStream &stream);
	bool parse_message(::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, const uint64_t size, BufferStream &stream);

	bool serialize_varint(const uint32_t wire_tag, const uint64_t val, BufferStream &stream) const;
	bool serialize_bool(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;
	bool serialize_int32(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;
	bool serialize_int64(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;
	bool serialize_uint32(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;
	bool serialize_uint64(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;
	bool serialize_float(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;
	bool serialize_double(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;
	bool serialize_string(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;
	bool serialize_message(const ::miniproto::ProtoField *field, const ::miniproto::ProtoFieldDescriptor *field_descriptor, BufferStream &stream) const;

	virtual void init_reflection() = 0;

protected:
	::miniproto::MessageDescriptor *message_descriptor_;
	ProtoFieldList *field_list_;
	::miniproto::MessageFactory *message_factory_;
};

} // namespace miniproto

#endif //_MESSAGE_H_
